package com.abl.core.service.sys.impl;


import com.abl.core.common.cache.Cache;
import com.abl.core.common.cache.CacheKey;
import com.abl.core.common.security.AuthUser;
import com.abl.core.common.util.AuthKit;
import com.abl.core.common.util.StringKit;
import com.abl.core.domain.db.LkRoleMenu;
import com.abl.core.domain.db.SysMenu;
import com.abl.core.domain.db.SysRole;
import com.abl.core.domain.project.MSG;
import com.abl.core.domain.project.ServiceException;
import com.abl.core.domain.project.PageSearch;
import com.abl.core.mybatis.mapper.LkRoleMenuMapper;
import com.abl.core.mybatis.mapper.SysRoleMapper;
import com.abl.core.service.sys.SysMenuService;
import com.abl.core.service.sys.SysRoleService;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.AntPathMatcher;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;

import static com.abl.core.domain.db.table.SysRoleTableDef.SYS_ROLE;

/**
 * 角色实现
 */
@Slf4j
@Service
public class SysRoleServiceImpl implements SysRoleService {
    @Resource
    private Cache<String> cache;

    @Resource
    private SysMenuService sysMenuService;

    @Resource
    private SysRoleMapper sysRoleMapper;

    @Resource
    private LkRoleMenuMapper roleMenuMapper;

    @Override
    public boolean insert(SysRole sysRole) {
        AuthUser authUser = AuthKit.mastLogin();
        String name = sysRole.getName();
        String id = sysRole.getId();

        if (StringKit.isBlank(name)) throw new ServiceException(MSG.PARAM_ER);
        if (authUser.isRoot()) if (StringKit.isBlank(id)) throw new ServiceException(MSG.PARAM_ER);


        //已存在名称
        QueryWrapper wrapper = QueryWrapper.create().from(SysRole.class).where(SYS_ROLE.NAME.eq(name));
        SysRole sysRole1 = sysRoleMapper.selectOneByQuery(wrapper);
        if (sysRole1 != null) throw new ServiceException(MSG.NAME_EXISTS);

        //ROOT用户需要已存在ID数据检查
        if (authUser.isRoot()) {
            wrapper = QueryWrapper.create().from(SysRole.class);
            wrapper.and(SYS_ROLE.ID.eq(id)).where(SYS_ROLE.DEL.in("0", "1"));
            sysRole1 = sysRoleMapper.selectOneByQuery(wrapper);
            if (sysRole1 != null) throw new ServiceException(MSG.ID_EXISTS);
        }

        long insert = sysRoleMapper.insertSelective(sysRole);

        //刷新缓存
        updateRoleResCache(sysRole.getId());

        return true;
    }

    @Override
    public boolean delete(String ids) {
        ArrayList<String> split = StringKit.split(ids);

        sysRoleMapper.deleteBatchByIds(split);

        //刷新缓存
        updateRoleResCache(split);

        return true;
    }

    @Override
    public boolean update(SysRole sysRole) {
        QueryWrapper where = QueryWrapper.create().from(SysRole.class).where("name = ?", sysRole.getName()).and("id !=?", sysRole.getId());
        if (sysRoleMapper.selectOneByQuery(where) != null) throw new ServiceException(MSG.NAME_EXISTS);

        sysRoleMapper.update(sysRole);

        //刷新缓存
        updateRoleResCache(sysRole.getId());

        return true;
    }

    @Override
    public SysRole info(String id) {
        QueryWrapper where = QueryWrapper.create().from(SysRole.class).where("id = ?", id);
        return sysRoleMapper.selectOneByQuery(where);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateRoleMenu(String roleId, String menuIds) {
        QueryWrapper where = QueryWrapper.create().select("id").from(SysRole.class).where("id = ?", roleId);
        if (sysRoleMapper.selectOneByQuery(where) == null) throw new ServiceException(MSG.ROLE_NOT_EXISTS);

        ArrayList<String> menuIdList = StringKit.split(menuIds);
        if (menuIdList.size() == 0) throw new ServiceException(MSG.PARAM_ER);

        //删除
        QueryWrapper where1 = QueryWrapper.create().where("role_id=?", roleId);

        long del = roleMenuMapper.deleteByQuery(where1);

        //插入
        ArrayList<LkRoleMenu> insertList = new ArrayList<>(menuIdList.size());
        for (String menuId : menuIdList) {
            LkRoleMenu lkRoleMenu = new LkRoleMenu();
            lkRoleMenu.setRoleId(roleId);
            lkRoleMenu.setMenuId(menuId);
            insertList.add(lkRoleMenu);
        }
        long insert = roleMenuMapper.insertBatch(insertList);

        //刷新缓存
        updateRoleResCache(roleId);

        return true;
    }

    @Override
    public List<SysRole> allMyRole() {
        AuthUser authUser = AuthKit.mastLogin();
        List<SysRole> sysRoles = sysRoleMapper.selectListByQuery(QueryWrapper.create());

        //root返回全部
        if (authUser.isRoot()) return sysRoles;

        String account = authUser.getAccount();
        List<String> roleIds = authUser.getRoleIds();

        //返回该用户创建的角色，不包含自身
        return sysRoles.stream().filter(e -> account.contains(e.getCa()) && !roleIds.contains(e.getId())).toList();
    }

    @Override
    public Page<SysRole> pageMyRole(SysRole sysRole, PageSearch pageSearch) {
        AuthUser authUser = AuthKit.mastLogin();
        QueryWrapper wrapper = QueryWrapper.create().select("*").from(SysRole.class)
                .where(SYS_ROLE.NAME.like(sysRole.getName())).orderBy(SYS_ROLE.SORT.asc()).orderBy(SYS_ROLE.CT.desc());;

        //返回该用户创建的角色，不包含自身
        if (!authUser.isRoot()) {
            wrapper.and(SYS_ROLE.CA.eq(authUser.getAccount())).and(SYS_ROLE.ID.notIn(authUser.getRoleIds()));
        }

        Page<SysRole> paginate = sysRoleMapper.paginate(pageSearch.getPageNumber(), pageSearch.getPageSize(), wrapper);
        List<SysRole> records = paginate.getRecords();
        //root返回全部
        for (SysRole role : records) {
            QueryWrapper where1 = QueryWrapper.create().select("menu_id").from(LkRoleMenu.class).where("role_id = ?", role.getId());
            List<Object> objects = sysRoleMapper.selectObjectListByQuery(where1);
            role.setMenuIds(objects);
        }
        return paginate;
    }


    @Override
    public ArrayList<String> roleHasRes(String roleId) {
        String resStr = cache.get(CacheKey.ROLE_HASE_RES + roleId);

        if (StringKit.isBlank(resStr)) {

            updateRoleResCache(roleId);

            resStr = cache.get(CacheKey.ROLE_HASE_RES + roleId);
            if (StringKit.isBlank(resStr)) return new ArrayList<>();
        }

        return StringKit.split(resStr);
    }

    @Override
    public ArrayList<String> roleHasRes(List<String> roleIds) {
        HashSet<String> resList = new HashSet<>();
        for (Object roleId : roleIds) {
            resList.addAll(roleHasRes(String.valueOf(roleId)));
        }
        return new ArrayList<>(resList);
    }


    @Override
    public ArrayList<String> roleExcludeRes(String roleId) {
        String resStr = cache.get(CacheKey.ROLE_EXCLUDE_RES + roleId);

        if (StringKit.isBlank(resStr)) {

            updateRoleResCache(roleId);

            resStr = cache.get(CacheKey.ROLE_EXCLUDE_RES + roleId);
            if (StringKit.isBlank(resStr)) return new ArrayList<>();
        }

        return StringKit.split(resStr);
    }

    @Override
    public ArrayList<String> roleExcludeRes(List<String> roleIds) {
        HashSet<String> resList = new HashSet<>();
        for (Object roleId : roleIds) {
            resList.addAll(roleExcludeRes(String.valueOf(roleId)));
        }
        return new ArrayList<>(resList);
    }

    //更新当前角色资源，存入缓存
    @Override
    public void updateRoleResCache(String roleId) {
        //查询全部资源
        List<String> menuIds = roleMenuMapper.selectObjectListByQueryAs(QueryWrapper.create().select("menu_id").where("role_id = ?", roleId), String.class);
        List<SysMenu> menuInfoList = sysMenuService.userHasMenu().stream().filter(e -> menuIds.contains(e.getId())).toList();
        List<String> resList = menuInfoList.stream().map(SysMenu::getRes).toList();
        SysRole sysRole = sysRoleMapper.selectOneById(roleId);

        //组装全部资源
        HashSet<String> haseRes = new HashSet<>();
        for (String resStr : resList) {
            haseRes.addAll(StringKit.split(resStr));
        }
        haseRes.addAll(StringKit.split(sysRole.getRes()));

        //查询全部排除资源
        HashSet<String> excludeRes = new HashSet<>();
        List<String> resExcludeList = menuInfoList.stream().map(SysMenu::getResExclude).toList();
        //组装全部排除资源
        for (String resExcludeStr : resExcludeList) {
            excludeRes.addAll(StringKit.split(resExcludeStr));
        }
        excludeRes.addAll(StringKit.split(sysRole.getResExclude()));

        //
        String haseResStr = StringKit.join(haseRes, ",");
        String excludeResStr = StringKit.join(excludeRes, ",");

        cache.set(CacheKey.ROLE_HASE_RES + roleId, haseResStr);
        cache.set(CacheKey.ROLE_EXCLUDE_RES + roleId, excludeResStr);

        log.info("全部资源 {}", haseRes);
        log.info("haseResStr {}", haseResStr);

        log.info("全部排除资源 {}", excludeRes);
        log.info("excludeResStr {}", excludeResStr);

    }

    @Override
    public void updateRoleResCache(List<String> roleIds) {
        for (String roleId : roleIds) {
            updateRoleResCache(roleId);
        }
    }

    //    判断角色是否具备 URI访问资格.
    @Override
    public boolean checkHasRes(String requestURI, AuthUser authUser) {
        return checkHasRes(authUser.getRoleIds(), requestURI);
    }

    //    判断角色是否具备 URI访问资格.
    @Override
    public boolean checkHasRes(String roleId, String requestURI) {
        return checkHasRes(Collections.singletonList(roleId), requestURI);
    }

    //    判断角色是否具备 URI访问资格.
    @Override
    public boolean checkHasRes(List<String> roleIds, String requestURI) {
        AntPathMatcher pathMatcher = new AntPathMatcher();

        //排除资源
        ArrayList<String> roleExcludeRes = roleExcludeRes(roleIds);
        for (String excludeRes : roleExcludeRes) {
            boolean matchExclude = pathMatcher.match(excludeRes, requestURI);
            if (matchExclude) return false;
        }

        //拥有资源
        ArrayList<String> roleHasRes = roleHasRes(roleIds);
        for (String hasRes : roleHasRes) {
            boolean matchHas = pathMatcher.match(hasRes, requestURI);
            if (matchHas) return true;
        }

        return false;
    }


}
